home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Developers / OutOfPhase1.01Source / OutOfPhase Folder / ExportAIFFSample.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-01  |  15.6 KB  |  474 lines  |  [TEXT/KAHL]

  1. /* ExportAIFFSample.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    Out Of Phase:  Digital Music Synthesis on General Purpose Computers    */
  5. /*    Copyright (C) 1994  Thomas R. Lawrence                                 */
  6. /*                                                                           */
  7. /*    This program is free software; you can redistribute it and/or modify   */
  8. /*    it under the terms of the GNU General Public License as published by   */
  9. /*    the Free Software Foundation; either version 2 of the License, or      */
  10. /*    (at your option) any later version.                                    */
  11. /*                                                                           */
  12. /*    This program is distributed in the hope that it will be useful,        */
  13. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  14. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
  15. /*    GNU General Public License for more details.                           */
  16. /*                                                                           */
  17. /*    You should have received a copy of the GNU General Public License      */
  18. /*    along with this program; if not, write to the Free Software            */
  19. /*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
  20. /*                                                                           */
  21. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  22. /*                                                                           */
  23. /*****************************************************************************/
  24.  
  25. #include "MiscInfo.h"
  26. #include "Audit.h"
  27. #include "Debug.h"
  28. #include "Definitions.h"
  29.  
  30. #include "ExportAIFFSample.h"
  31. #include "Memory.h"
  32. #include "SampleConsts.h"
  33. #include "Files.h"
  34. #include "SampleStorageActual.h"
  35. #include "BufferedFileOutput.h"
  36. #include "Alert.h"
  37.  
  38.  
  39. /* prototype for the function that actually does the work. */
  40. static void                    TryToExportAIFF(SampleStorageActualRec* Sample,
  41.                                             BufferedOutputRec* File, long SamplingRate);
  42.  
  43.  
  44. /* this routine saves the data in the provided sample storage object as an AIFF-C */
  45. /* formatted file.  it handles any error reporting to the user.  the object is */
  46. /* NOT disposed, so the caller has to do that. */
  47. void                                ExportAIFFSample(struct SampleStorageActualRec* TheSample,
  48.                                             long SamplingRate)
  49.     {
  50.         FileSpec*                    WhereToPut;
  51.  
  52.         CheckPtrExistence(TheSample);
  53.         WhereToPut = PutFile("Untitled.AIFF");
  54.         if (WhereToPut != NIL)
  55.             {
  56.                 if (CreateFile(WhereToPut,CODE4BYTES('?','?','?','?'),
  57.                     CODE4BYTES('?','?','?','?')))
  58.                     {
  59.                         FileType*                    FileDesc;
  60.  
  61.                         if (OpenFile(WhereToPut,&FileDesc,eReadAndWrite))
  62.                             {
  63.                                 BufferedOutputRec*    File;
  64.  
  65.                                 File = NewBufferedOutput(FileDesc);
  66.                                 if (File != NIL)
  67.                                     {
  68.                                         TryToExportAIFF(TheSample,File,SamplingRate);
  69.                                         EndBufferedOutput(File);
  70.                                     }
  71.                                  else
  72.                                     {
  73.                                         AlertHalt("There is not enough memory available to export the sample.",NIL);
  74.                                     }
  75.                                 CloseFile(FileDesc);
  76.                             }
  77.                          else
  78.                             {
  79.                                 AlertHalt("Unable to open the file for writing.",NIL);
  80.                             }
  81.                     }
  82.                  else
  83.                     {
  84.                         AlertHalt("Unable to create the file.",NIL);
  85.                     }
  86.                 DisposeFileSpec(WhereToPut);
  87.             }
  88.     }
  89.  
  90.  
  91. /* AIFF/AIFF-C File Format: */
  92. /*     "FORM" */
  93. /*     4-byte big endian form chunk length descriptor (minus 8 for "FORM" & this) */
  94. /*     4-byte type */
  95. /*        "AIFF" = AIFF format file */
  96. /*        "AIFC" = AIFF-C format file */
  97. /* in any order, these chunks can occur: */
  98. /*   Version Chunk (this only occurs in AIFF-C files) */
  99. /*     "FVER" */
  100. /*     4-byte big endian length, which should always be the value 4 (four) */
  101. /*     4-byte date code.  this is probably 0xA2805140 (stored big endian), but it */
  102. /*          probably doesn't matter. */
  103. /*   Common Chunk for AIFF files */
  104. /*     "COMM" */
  105. /*     4-byte big endian length. */
  106. /*        always 18 for AIFF files */
  107. /*     2-byte big endian number of channels */
  108. /*     4-byte big endian number of sample frames */
  109. /*     2-byte big endian number of bits per sample */
  110. /*        a value in the domain 1..32 */
  111. /*     10-byte extended precision number of frames per second */
  112. /*   Common Chunk for AIFF-C files */
  113. /*     "COMM" */
  114. /*     4-byte big endian length. */
  115. /*        22 + compression method string length for AIFF-C files */
  116. /*     2-byte big endian number of channels */
  117. /*     4-byte big endian number of sample frames */
  118. /*     2-byte big endian number of bits per sample */
  119. /*        a value in the domain 1..32 */
  120. /*     10-byte extended precision number of frames per second */
  121. /*     4-byte character code ID for the compression method */
  122. /*        "NONE" means there is no compression method used */
  123. /*     some characters in a string identifying the compression method */
  124. /*        this must be padded to an even number of bytes, but the pad is */
  125. /*        NOT included in the length descriptor for the chunk. */
  126. /*        for uncompressed data, the string should be */
  127. /*        "\x0enot compressed\x00", including the null, for 16 bytes. */
  128. /*        the total chunk length is thus 38 bytes. */
  129. /*   Sound Data Chunk */
  130. /*     "SSND" */
  131. /*     4-byte big endian number of bytes in sample data array */
  132. /*     4-byte big endian offset to the first byte of sample data in the array */
  133. /*     4-byte big endian number of bytes to which the sound data is aligned. */
  134. /*     any length vector of raw sound data. */
  135. /*        this must be padded to an even number of bytes, but the pad is */
  136. /*        NOT included in the length descriptor for the chunk. */
  137. /*        Samples are stored in an integral number of bytes, the smallest that */
  138. /*        is required for the specified number of bits.  If this is not an even */
  139. /*        multiple of 8, then the data is shifted left and the low bits are zeroed */
  140. /*        Multichannel sound is interleaved with the left channel first. */
  141. static void                    TryToExportAIFF(SampleStorageActualRec* Sample,
  142.                                             BufferedOutputRec* File, long SamplingRate)
  143.     {
  144.         long                            NumSampleFrames;
  145.         long                            BytesPerFrame;
  146.         long                            ActualBytesInTheSampleChunk;
  147.         long                            BytesInTheFormChunk;
  148.         long                            NumberOfChannels;
  149.         long                            BitDepthOfSamples;
  150.         unsigned long            Mantissa;
  151.         unsigned long            Exponent;
  152.         char                            StupidExtendedThing[10];
  153.  
  154.         CheckPtrExistence(Sample);
  155.         CheckPtrExistence(File);
  156.  
  157.         NumSampleFrames = GetSampleStorageActualNumFrames(Sample);
  158.  
  159.         BytesPerFrame = 1;
  160.         switch (GetSampleStorageActualNumChannels(Sample))
  161.             {
  162.                 default:
  163.                     EXECUTE(PRERR(ForceAbort,"TryToExportAIFF:  bad value from "
  164.                         "GetSampleStorageActualNumChannels"));
  165.                     break;
  166.                 case eSampleStereo:
  167.                     NumberOfChannels = 2;
  168.                     break;
  169.                 case eSampleMono:
  170.                     NumberOfChannels = 1;
  171.                     break;
  172.             }
  173.         BytesPerFrame *= NumberOfChannels;
  174.  
  175.         switch (GetSampleStorageActualNumBits(Sample))
  176.             {
  177.                 default:
  178.                     EXECUTE(PRERR(ForceAbort,"TryToExportAIFF:  bad value from "
  179.                         "GetSampleStorageActualNumBits"));
  180.                     break;
  181.                 case eSample16bit:
  182.                     BitDepthOfSamples = 16;
  183.                     break;
  184.                 case eSample8bit:
  185.                     BitDepthOfSamples = 8;
  186.                     break;
  187.             }
  188.         BytesPerFrame *= (BitDepthOfSamples / 8);
  189.  
  190.         /* extended 22050 = 400D AC44000000000000 */
  191.         /* extended 22051 = 400D AC46000000000000 */
  192.         /* extended 44100 = 400E AC44000000000000 */
  193.         /* extended 44101 = 400E AC45000000000000 */
  194.         Exponent = 0x401e;
  195.         Mantissa = SamplingRate;
  196.         while ((Mantissa & 0x80000000) == 0)
  197.             {
  198.                 Mantissa = Mantissa << 1;
  199.                 Exponent -= 1;
  200.             }
  201.         StupidExtendedThing[0] = (Exponent >> 8) & 0xff;
  202.         StupidExtendedThing[1] = Exponent & 0xff;
  203.         StupidExtendedThing[2] = (Mantissa >> 24) & 0xff;
  204.         StupidExtendedThing[3] = (Mantissa >> 16) & 0xff;
  205.         StupidExtendedThing[4] = (Mantissa >> 8) & 0xff;
  206.         StupidExtendedThing[5] = Mantissa & 0xff;
  207.         StupidExtendedThing[6] = 0;
  208.         StupidExtendedThing[7] = 0;
  209.         StupidExtendedThing[8] = 0;
  210.         StupidExtendedThing[9] = 0;
  211.  
  212.         ActualBytesInTheSampleChunk = BytesPerFrame * NumSampleFrames;
  213.         if ((ActualBytesInTheSampleChunk % 2) != 0)
  214.             {
  215.                 ActualBytesInTheSampleChunk += 1;
  216.             }
  217.  
  218.         BytesInTheFormChunk = (ActualBytesInTheSampleChunk + 8) + (38 + 8) + (12);
  219.  
  220.         /*     "FORM" */
  221.         if (!WriteBufferedOutput(File,4,"FORM"))
  222.             {
  223.              DiskErrorPoint:
  224.                 AlertHalt("Unable to write to the file.",NIL);
  225.                 return;
  226.             }
  227.  
  228.         /*     4-byte big endian form chunk length descriptor (minus 8 for "FORM" & this) */
  229.         if (!WriteBufferedUnsignedLongBigEndian(File,BytesInTheFormChunk))
  230.             {
  231.                 goto DiskErrorPoint;
  232.             }
  233.  
  234.         /*     4-byte type */
  235.         /*        "AIFF" = AIFF format file */
  236.         /*        "AIFC" = AIFF-C format file */
  237.         if (!WriteBufferedOutput(File,4,"AIFC"))
  238.             {
  239.                 goto DiskErrorPoint;
  240.             }
  241.  
  242.         /*   Version Chunk (this only occurs in AIFF-C files) */
  243.  
  244.         /*     "FVER" */
  245.         if (!WriteBufferedOutput(File,4,"FVER"))
  246.             {
  247.                 goto DiskErrorPoint;
  248.             }
  249.  
  250.         /*     4-byte big endian length, which should always be the value 4 (four) */
  251.         if (!WriteBufferedUnsignedLongBigEndian(File,4))
  252.             {
  253.                 goto DiskErrorPoint;
  254.             }
  255.  
  256.         /*     4-byte date code.  this is probably 0xA2805140 (stored big endian), but it */
  257.         /*          probably doesn't matter. */
  258.         if (!WriteBufferedOutput(File,4,"\xa2\x80\x51\x40"))
  259.             {
  260.                 goto DiskErrorPoint;
  261.             }
  262.  
  263.         /*   Common Chunk for AIFF-C files */
  264.  
  265.         /*     "COMM" */
  266.         if (!WriteBufferedOutput(File,4,"COMM"))
  267.             {
  268.                 goto DiskErrorPoint;
  269.             }
  270.  
  271.         /*     4-byte big endian length. */
  272.         /*        22 + compression method string length for AIFF-C files */
  273.         if (!WriteBufferedUnsignedLongBigEndian(File,38))
  274.             {
  275.                 goto DiskErrorPoint;
  276.             }
  277.  
  278.         /*     2-byte big endian number of channels */
  279.         if (!WriteBufferedUnsignedShortBigEndian(File,NumberOfChannels))
  280.             {
  281.                 goto DiskErrorPoint;
  282.             }
  283.  
  284.         /*     4-byte big endian number of sample frames */
  285.         if (!WriteBufferedUnsignedLongBigEndian(File,NumSampleFrames))
  286.             {
  287.                 goto DiskErrorPoint;
  288.             }
  289.  
  290.         /*     2-byte big endian number of bits per sample */
  291.         /*        a value in the domain 1..32 */
  292.         if (!WriteBufferedUnsignedShortBigEndian(File,BitDepthOfSamples))
  293.             {
  294.                 goto DiskErrorPoint;
  295.             }
  296.  
  297.         /*     10-byte extended precision number of frames per second */
  298.         if (!WriteBufferedOutput(File,10,StupidExtendedThing))
  299.             {
  300.                 goto DiskErrorPoint;
  301.             }
  302.  
  303.         /*     4-byte character code ID for the compression method */
  304.         /*        "NONE" means there is no compression method used */
  305.         if (!WriteBufferedOutput(File,4,"NONE"))
  306.             {
  307.                 goto DiskErrorPoint;
  308.             }
  309.  
  310.         /*     some characters in a string identifying the compression method */
  311.         /*        this must be padded to an even number of bytes, but the pad is */
  312.         /*        NOT included in the length descriptor for the chunk. */
  313.         /*        for uncompressed data, the string should be */
  314.         /*        "\x0enot compressed\x00", including the null, for 16 bytes. */
  315.         /*        the total chunk length is thus 38 bytes. */
  316.         if (!WriteBufferedOutput(File,16,"\x0enot compressed\x00"))
  317.             {
  318.                 goto DiskErrorPoint;
  319.             }
  320.  
  321.         /*   Sound Data Chunk */
  322.  
  323.         /*     "SSND" */
  324.         if (!WriteBufferedOutput(File,4,"SSND"))
  325.             {
  326.                 goto DiskErrorPoint;
  327.             }
  328.  
  329.         /*     4-byte big endian number of bytes in sample data array */
  330.         if (!WriteBufferedUnsignedLongBigEndian(File,BytesPerFrame * NumSampleFrames))
  331.             {
  332.                 goto DiskErrorPoint;
  333.             }
  334.  
  335.         /*     4-byte big endian offset to the first byte of sample data in the array */
  336.         if (!WriteBufferedUnsignedLongBigEndian(File,0))
  337.             {
  338.                 goto DiskErrorPoint;
  339.             }
  340.  
  341.         /*     4-byte big endian number of bytes to which the sound data is aligned. */
  342.         if (!WriteBufferedUnsignedLongBigEndian(File,0))
  343.             {
  344.                 goto DiskErrorPoint;
  345.             }
  346.  
  347.         /*     any length vector of raw sound data. */
  348.         /*        this must be padded to an even number of bytes, but the pad is */
  349.         /*        NOT included in the length descriptor for the chunk. */
  350.         /*        Samples are stored in an integral number of bytes, the smallest that */
  351.         /*        is required for the specified number of bits.  If this is not an even */
  352.         /*        multiple of 8, then the data is shifted left and the low bits are zeroed */
  353.         /*        Multichannel sound is interleaved with the left channel first. */
  354.         switch (GetSampleStorageActualNumChannels(Sample))
  355.             {
  356.                 default:
  357.                     EXECUTE(PRERR(ForceAbort,"TryToExportAIFF:  bad value from "
  358.                         "GetSampleStorageActualNumChannels"));
  359.                     break;
  360.                 case eSampleStereo:
  361.                     switch (GetSampleStorageActualNumBits(Sample))
  362.                         {
  363.                             default:
  364.                                 EXECUTE(PRERR(ForceAbort,"TryToExportAIFF:  bad value from "
  365.                                     "GetSampleStorageActualNumBits"));
  366.                                 break;
  367.                             case eSample16bit:
  368.                                 {
  369.                                     long                        Scan;
  370.  
  371.                                     for (Scan = 0; Scan < NumSampleFrames; Scan += 1)
  372.                                         {
  373.                                             largefixedsigned        SampleWord;
  374.  
  375.                                             SampleWord = GetSampleStorageActualValue(Sample,Scan,eLeftChannel);
  376.                                             if (!WriteBufferedSignedShortBigEndian(File,
  377.                                                 roundtonearest(largefixed2double(SampleWord) * MAX16BIT)))
  378.                                                 {
  379.                                                     goto DiskErrorPoint;
  380.                                                 }
  381.                                             SampleWord = GetSampleStorageActualValue(Sample,Scan,eRightChannel);
  382.                                             if (!WriteBufferedSignedShortBigEndian(File,
  383.                                                 roundtonearest(largefixed2double(SampleWord) * MAX16BIT)))
  384.                                                 {
  385.                                                     goto DiskErrorPoint;
  386.                                                 }
  387.                                         }
  388.                                     /* 16-bit is always even aligned */
  389.                                 }
  390.                                 break;
  391.                             case eSample8bit:
  392.                                 {
  393.                                     long                        Scan;
  394.  
  395.                                     for (Scan = 0; Scan < NumSampleFrames; Scan += 1)
  396.                                         {
  397.                                             largefixedsigned        SampleWord;
  398.  
  399.                                             SampleWord = GetSampleStorageActualValue(Sample,Scan,eLeftChannel);
  400.                                             if (!WriteBufferedSignedChar(File,
  401.                                                 roundtonearest(largefixed2double(SampleWord) * MAX8BIT)))
  402.                                                 {
  403.                                                     goto DiskErrorPoint;
  404.                                                 }
  405.                                             SampleWord = GetSampleStorageActualValue(Sample,Scan,eRightChannel);
  406.                                             if (!WriteBufferedSignedChar(File,
  407.                                                 roundtonearest(largefixed2double(SampleWord) * MAX8BIT)))
  408.                                                 {
  409.                                                     goto DiskErrorPoint;
  410.                                                 }
  411.                                         }
  412.                                     /* stereo is always even aligned */
  413.                                 }
  414.                                 break;
  415.                         }
  416.                     break;
  417.                 case eSampleMono:
  418.                     switch (GetSampleStorageActualNumBits(Sample))
  419.                         {
  420.                             default:
  421.                                 EXECUTE(PRERR(ForceAbort,"TryToExportAIFF:  bad value from "
  422.                                     "GetSampleStorageActualNumBits"));
  423.                                 break;
  424.                             case eSample16bit:
  425.                                 {
  426.                                     long                        Scan;
  427.  
  428.                                     for (Scan = 0; Scan < NumSampleFrames; Scan += 1)
  429.                                         {
  430.                                             largefixedsigned        SampleWord;
  431.  
  432.                                             SampleWord = GetSampleStorageActualValue(Sample,Scan,eMonoChannel);
  433.                                             if (!WriteBufferedSignedShortBigEndian(File,
  434.                                                 roundtonearest(largefixed2double(SampleWord) * MAX16BIT)))
  435.                                                 {
  436.                                                     goto DiskErrorPoint;
  437.                                                 }
  438.                                         }
  439.                                     /* 16-bit is always even aligned */
  440.                                 }
  441.                                 break;
  442.                             case eSample8bit:
  443.                                 {
  444.                                     long                        Scan;
  445.  
  446.                                     for (Scan = 0; Scan < NumSampleFrames; Scan += 1)
  447.                                         {
  448.                                             largefixedsigned        SampleWord;
  449.  
  450.                                             SampleWord = GetSampleStorageActualValue(Sample,Scan,eMonoChannel);
  451.                                             if (!WriteBufferedSignedChar(File,
  452.                                                 roundtonearest(largefixed2double(SampleWord) * MAX8BIT)))
  453.                                                 {
  454.                                                     goto DiskErrorPoint;
  455.                                                 }
  456.                                         }
  457.                                     /* 8-bit mono might be unaligned */
  458.                                     if ((NumSampleFrames % 2) != 0)
  459.                                         {
  460.                                             /* write an extra pad byte */
  461.                                             if (!WriteBufferedUnsignedChar(File,0))
  462.                                                 {
  463.                                                     goto DiskErrorPoint;
  464.                                                 }
  465.                                         }
  466.                                 }
  467.                                 break;
  468.                         }
  469.                     break;
  470.             }
  471.  
  472.         /* all done */
  473.     }
  474.